package com.tripcube.ai.service.impl;

import com.tripcube.ai.model.dto.RagChatDTO;
import com.tripcube.ai.model.dto.MemoryChatDTO;
import com.tripcube.ai.model.vo.BaseChatVO;
import com.tripcube.ai.service.KnowledgeRetrievalService;
import com.tripcube.ai.service.MemoryChatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.util.List;

import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;

/**
 * 记忆聊天服务实现类
 * 实现具有上下文记忆功能的AI聊天服务，支持多种聊天模式和角色设定
 * 
 * @author alander
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MemoryChatServiceImpl implements MemoryChatService {

    /**
     * MySQL记忆聊天客户端
     */
    private final ChatClient mysqlMemoryChatClient;
    
    /**
     * 消息窗口聊天记忆管理器
     */
    private final MessageWindowChatMemory messageWindowChatMemory;
    
    /**
     * 知识检索服务
     */
    private final KnowledgeRetrievalService knowledgeRetrievalService;

    /**
     * 记忆聊天实现
     * 根据请求内容进行聊天交互，如果请求中包含自定义系统提示，则使用该提示；否则使用默认配置
     *
     * @param request 包含聊天相关信息的请求对象，包括系统提示、用户查询和会话ID
     * @return AI 返回的聊天响应内容
     */
    @Override
    public String chat(MemoryChatDTO request) {
        log.info("开始记忆聊天，会话ID: {}, 查询内容: {}", 
                request.getConversationId(), request.getQuery());
        
        String response;
        // 如果请求中包含自定义系统提示，则使用它
        if (StringUtils.hasText(request.getSystemPrompt())) {
            log.debug("使用自定义系统提示: {}", request.getSystemPrompt());
            response = mysqlMemoryChatClient.prompt()
                    .system(request.getSystemPrompt()) // 动态设置系统提示
                    .user(request.getQuery())
                    .advisors(
                            a -> a.param(CONVERSATION_ID, request.getConversationId())
                    )
                    .call().content();
        } else {
            // 使用默认配置
            log.debug("使用默认系统配置");
            response = mysqlMemoryChatClient.prompt(request.getQuery())
                    .advisors(
                            a -> a.param(CONVERSATION_ID, request.getConversationId())
                    )
                    .call().content();
        }
        
        log.info("记忆聊天完成，会话ID: {}, 响应长度: {} 字符", 
                request.getConversationId(), response.length());
        return response;
    }

    /**
     * 流式记忆聊天实现
     * 根据请求内容进行流式聊天交互，支持自定义系统提示
     *
     * @param request 记忆聊天请求参数
     * @return 流式聊天响应
     */
    @Override
    public Flux<String> streamChat(MemoryChatDTO request) {
        log.info("开始流式记忆聊天，会话ID: {}, 查询内容: {}", 
                request.getConversationId(), request.getQuery());
        
        Flux<String> responseFlux;
        if (StringUtils.hasText(request.getSystemPrompt())) {
            log.debug("使用自定义系统提示进行流式聊天");
            responseFlux = mysqlMemoryChatClient.prompt()
                    .system(request.getSystemPrompt())
                    .user(request.getQuery())
                    .advisors(
                            a -> a.param(CONVERSATION_ID, request.getConversationId())
                    )
                    .stream()
                    .content();
        } else {
            // 使用默认配置
            log.debug("使用默认配置进行流式聊天");
            responseFlux = mysqlMemoryChatClient.prompt(request.getQuery())
                    .advisors(
                            a -> a.param(CONVERSATION_ID, request.getConversationId())
                    )
                    .stream()
                    .content();
        }
        
        return responseFlux.doOnComplete(() -> 
                log.info("流式记忆聊天完成，会话ID: {}", request.getConversationId()))
                .doOnError(error -> 
                log.error("流式记忆聊天出错，会话ID: {}, 错误: {}", 
                        request.getConversationId(), error.getMessage()));
    }

    /**
     * 获取会话历史消息实现
     * 根据会话ID获取该会话的所有历史消息记录
     *
     * @param conversationId 会话唯一标识符
     * @return 指定会话中的所有消息列表
     */
    @Override
    public List<Message> getMessages(String conversationId) {
        log.info("获取会话历史消息，会话ID: {}", conversationId);
        
        List<Message> messages = messageWindowChatMemory.get(conversationId);
        
        log.info("获取到 {} 条历史消息，会话ID: {}", 
                messages != null ? messages.size() : 0, conversationId);
        
        return messages;
    }

    /**
     * 带角色的记忆聊天实现
     * 根据指定角色进行聊天交互，不同角色对应不同的系统提示语，用于引导AI以特定身份进行回答
     *
     * @param request 包含聊天相关信息的请求对象，包括用户查询和会话ID
     * @param role    用户指定的角色名称
     * @return AI 返回的聊天响应内容
     */
    @Override
    public String chatWithRole(MemoryChatDTO request, String role) {
        log.info("开始角色聊天，会话ID: {}, 角色: {}, 查询内容: {}", 
                request.getConversationId(), role, request.getQuery());
        
        String systemPrompt = switch (role.toLowerCase()) {
            case "teacher" -> "你是一位经验丰富的教师，请用教育者的角度回答问题。";
            case "doctor" -> "你是一位专业的医生，请提供医学相关的建议和信息。";
            case "programmer" -> "你是一位资深程序员，请用技术专家的角度回答编程相关问题。";
            default -> "你是一个博学的智能聊天助手，请根据用户提问回答！";
        };
        
        log.debug("使用角色系统提示: {}", systemPrompt);

        String response = mysqlMemoryChatClient.prompt()
                .system(systemPrompt)
                .user(request.getQuery())
                .advisors(
                        a -> a.param(CONVERSATION_ID, request.getConversationId())
                )
                .call().content();
                
        log.info("角色聊天完成，会话ID: {}, 角色: {}, 响应长度: {} 字符", 
                request.getConversationId(), role, response.length());
                
        return response;
    }

    /**
     * 带角色的流式记忆聊天实现
     * 根据指定角色进行流式聊天交互，支持实时响应
     *
     * @param request 记忆聊天请求参数
     * @param role    用户指定的角色名称
     * @return 流式聊天响应
     */
    @Override
    public Flux<String> streamChatWithRole(MemoryChatDTO request, String role) {
        log.info("开始流式角色聊天，会话ID: {}, 角色: {}, 查询内容: {}", 
                request.getConversationId(), role, request.getQuery());
        
        String systemPrompt = switch (role.toLowerCase()) {
            case "teacher" -> "你是一位经验丰富的教师，请用教育者的角度回答问题。";
            case "doctor" -> "你是一位专业的医生，请提供医学相关的建议和信息。";
            case "programmer" -> "你是一位资深程序员，请用技术专家的角度回答编程相关问题。";
            default -> "你是一个博学的智能聊天助手，请根据用户提问回答！";
        };
        
        log.debug("使用角色系统提示进行流式聊天: {}", systemPrompt);

        return mysqlMemoryChatClient.prompt()
                .system(systemPrompt)
                .user(request.getQuery())
                .advisors(
                        a -> a.param(CONVERSATION_ID, request.getConversationId())
                )
                .stream()
                .content()
                .doOnComplete(() -> 
                        log.info("流式角色聊天完成，会话ID: {}, 角色: {}", 
                                request.getConversationId(), role))
                .doOnError(error -> 
                        log.error("流式角色聊天出错，会话ID: {}, 角色: {}, 错误: {}", 
                                request.getConversationId(), role, error.getMessage()));
    }

    /**
     * RAG聊天实现
     * 基于检索增强生成(RAG)技术的同步聊天，目前暂未实现
     *
     * @param request RAG聊天请求参数
     * @return 聊天响应结果
     */
    @Override
    public BaseChatVO ragChat(RagChatDTO request) {
        log.warn("RAG聊天功能暂未实现，请求参数: {}", request);
        // TODO: 实现RAG聊天功能
        return null;
    }

    /**
     * RAG流式聊天实现
     * 基于检索增强生成(RAG)技术的流式聊天，目前暂未实现
     *
     * @param request RAG聊天请求参数
     * @return 流式聊天响应
     */
    @Override
    public Flux<String> ragStreamChat(RagChatDTO request) {
        log.warn("RAG流式聊天功能暂未实现，请求参数: {}", request);
        // TODO: 实现RAG流式聊天功能
        return null;
    }
}

